package com.chezhujie.www.controller.api;

import com.alibaba.fastjson.JSONObject;
import com.chezhujie.www.core.StaticMap;
import com.chezhujie.www.domain.Czjcommodity;
import com.chezhujie.www.domain.Czjorder;
import com.chezhujie.www.domain.Czjorderdetail;
import com.chezhujie.www.domain.vo.AccessToken;
import com.chezhujie.www.domain.vo.WeixinInfo;
import com.chezhujie.www.service.*;
import com.xy.core.utils.LocalDateTime;
import com.xy.user.base.controller.BaseController;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import weixin.popular.api.PayMchAPI;
import weixin.popular.bean.paymch.*;
import weixin.popular.support.ExpireKey;
import weixin.popular.support.expirekey.DefaultExpireKey;
import weixin.popular.util.PayUtil;
import weixin.popular.util.SignatureUtil;
import weixin.popular.util.StreamUtils;
import weixin.popular.util.XMLConverUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


/**
 * Created by 汤伟杰 on 2017/5/8.
 */
@Controller
@RequestMapping("/api/weixin")
public class WeixinController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(WeixinController.class);
    @Autowired
    private WeixininfoService weixininfoService;
    @Autowired
    private CzjorderService czjorderService;
    @Autowired
    private CzjactivityService czjactivityService;
    @Autowired
    private CzjtordermemberService czjtordermemberService;
    @Autowired
    private CzjuserinfoService czjuserinfoService;
    @Autowired
    private CzjusermessService czjusermessService;
    @Autowired
    private CzjweixinvoucherService czjweixinvoucherService;
    @Autowired
    private CzjpayorderService czjpayorderService;
    @Autowired
    private CzjawarduseService czjawarduseService;
    @Autowired
    private CzjorderdetailService czjorderdetailService;
    @Autowired
    private CzjcommodityService czjcommodityService;
    @Autowired
    private CzjweixininfoService czjweixininfoService;
    @Autowired
    private CzjawardstockService czjawardstockService;
    @Autowired
    private CzjusecouponService czjusecouponService;
    @Autowired
    private CzjorderdistributionService czjorderdistributionService;
    @Autowired
    private CzjdeliveryaddService czjdeliveryaddService;



    /**
     * 跳转微信授权页面
     * @param returnUrl
     * @param req
     * @param resp
     * @param model
     * @return
     */
    @RequestMapping("getWeixinAuth.jn")
    public String getWeixinAuth(@RequestParam(required = true) String returnUrl , HttpServletRequest req, HttpServletResponse resp,
                                ModelMap model){
        String url = returnUrl;
        url=getURLEncoderString(url);
        model.addAttribute("url", url);
        model.addAttribute("appid", StaticMap.appid);
        return "weixinLogin";

    }


    /**
     * URL 转码
     *
     * @return String
     * @author lifq
     * @date 2015-3-17 下午04:10:28
     */
    private String getURLEncoderString(String str) {
        String result = "";
        if (null == str) {
            return "";
        }
        try {
            result = java.net.URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取微信用户信息
     * @param code
     * @param req
     * @param resp
     * @param model
     * @throws Exception
     */
    @RequestMapping("getWeixinInfo.jn")
    public void getOpenId(@RequestParam(required = true) String code,
                         String appid,String secret,
                         Integer userinfoId,
                        HttpServletRequest req, HttpServletResponse resp,
                        ModelMap model) throws Exception {
        try {
            if(StringUtils.isBlank(appid)){
                appid = StaticMap.appid;
            }
            if(StringUtils.isBlank(secret)){
                secret = StaticMap.secret;
            }
            WeixinInfo weixin = weixininfoService.getWeixinInfo(code, appid, secret);
            jsonResult(1,"","",weixininfoService.getWeixinInfo(code,appid,secret),resp);
        } catch (Exception e) {
            e.printStackTrace();
            jsonResult(0,"99","获取微信信息出错！"+e.getMessage(),"",resp);
        }


    }





    /**
     * 支付 配置验证信息
     * @param request
     * @param response
     * @param model
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("payMchjs.jn")
    public void payMchJs(@RequestParam(required = true)String openId,
                         @RequestParam(required = true)String orderNo,//支付订单号
            String appid2,
                         HttpServletRequest request, HttpServletResponse response,
                          ModelMap model) throws Exception {

        try {

            String path = request.getRequestURL().substring(0, request.getRequestURL().lastIndexOf("/"))+"/payMchNotify.jn";
            String notifyUrl = path;//支付回调链接
//        openId = "oRYMns_SBJTs5-FQREG3aACMSE-Q";

            String appid=StaticMap.appid;
            String mch_id=StaticMap.mch_id;
            String wx_openid = openId;//"oRYMns_SBJTs5-FQREG3aACMSE-Q"
            String key = StaticMap.payKey;

            if(StringUtils.isNotBlank(appid2)){
                appid=appid2;
            }



            String title = "商品信息";
            String money = "";//单位分 0.01元
            Map<String, Object> order = new HashMap<String, Object>();
            String type = orderNo.substring(8,9);
            Map<String, Object> mapresult = null;
            if("1".equals(type)){//租赁商品
                mapresult = getTitleAndMoney1(orderNo);
            }else if("2".equals(type)) {//购买商品
                mapresult = getTitleAndMoney2(orderNo);
            }else if("3".equals(type)){
                mapresult = getTitleAndMoney3(orderNo);
           }else{
                jsonResult(0,"72","支付类型不正确，只能是1（活动）或者2（商品）","",response);
                return;
            }
            if(null==mapresult.get("status")||0==(Integer)mapresult.get("status")){
                jsonResult((int)mapresult.get("status"),(String)mapresult.get("code"),(String)mapresult.get("msg"),"",response);
                return;
            }
            order = (Map<String,Object>)mapresult.get("result");
            if(order==null|| StringUtils.isBlank(String.valueOf(order.get("money")))){
                jsonResult(0,"73","订单不存在或者订单金额信息为空","",response);
                return;
            }
            //payPackage 的商品信息,openid 可以通过sns,或事件获取。
           if(null==order.get("title")){
                title="社聚共享-订单支付";
            }else{
                title = String.valueOf(order.get("title"));
                if(title.length()>=50){
                    title = title.substring(0,50);
                }
            }

            money = String.valueOf(order.get("money"));

            Unifiedorder unifiedorder = new Unifiedorder();
            unifiedorder.setAppid(appid);
            unifiedorder.setMch_id(mch_id);
            unifiedorder.setNonce_str(UUID.randomUUID().toString().toString().replace("-", ""));

            unifiedorder.setOpenid(wx_openid);
            unifiedorder.setBody(title);
            unifiedorder.setOut_trade_no(orderNo);
            unifiedorder.setTotal_fee(new BigDecimal(money).multiply(new BigDecimal(100)).intValue()+"");//单位分 0.01元
            unifiedorder.setSpbill_create_ip(request.getRemoteAddr());//IP
            unifiedorder.setNotify_url(notifyUrl);
            unifiedorder.setTrade_type("JSAPI");//JSAPI，NATIVE，APP，WAP
            //统一下单，生成预支付订单
            UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder,key);

            if(!"SUCCESS".equals(unifiedorderResult.getReturn_code())){
                jsonResult(0,"89",unifiedorderResult.getReturn_msg(),"",response);
                return;
            }
            if(!"SUCCESS".equals(unifiedorderResult.getResult_code())){
                jsonResult(0,"89",unifiedorderResult.getErr_code()+"-"+unifiedorderResult.getErr_code_des(),"",response);
                return;
            }

            //@since 2.8.5  API返回数据签名验证
            if(unifiedorderResult.getSign_status() !=null && unifiedorderResult.getSign_status()){
                MchBase mb = unifiedorderResult;
                if("FAIL".equals(mb.getResult_code())){
                    jsonResult(0,mb.getErr_code_des().split(" ")[0],mb.getErr_code_des().split(" ")[1],"",response);
                    return;
                }
                String json = PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appid, key);

                Map map = JSONObject.parseObject(json, Map.class);
                jsonResult(1,"",JSONObject.toJSONString(unifiedorder),map,response);
                return;
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("",e);
        }
        jsonResult(0,"89","请求支付失败！","",response);
    }

    private Map<String,Object> getTitleAndMoney3(String orderNo) {
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> map = new HashMap<>();

        Czjorderdetail czjorderdetail = czjorderdetailService.queryByLeaseNum(orderNo);
        Map<String, Object> order;
        if(czjorderdetail==null){
            putData(data,0,"73","租赁结算订单不存在");
            return data;
        }

        putData(data,1,"","");
        map.put("title","租赁结算订单："+orderNo);
        map.put("money",czjorderdetail.getEndLeaseAmount());
        data.put("result", map);
        return data;
    }


    //租赁商品生成验证信息
    private Map<String,Object> getTitleAndMoney1(String orderNo) {
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> param = new HashMap<>();
        param.put("orderCode", orderNo);
        Czjorder order = czjorderService.getOneBy(param);

        Czjorderdetail czjorderdetail = czjorderdetailService.queryByCode(orderNo);
        if(order==null){
            putData(data,0,"73","订单不存在");
            return data;
        }
        Czjcommodity commodity = czjcommodityService.queryById(czjorderdetail.getCommodityId());
        if(commodity.getDelFlag()==1||commodity.getSoldOut()==1){
            System.out.println(LocalDateTime.getDateStr(new Date())+"    "+"商品已下架，请手动取消订单！");
            putData(data,0,"71","商品已下架，请手动取消订单！");
            return data;
        }
        putData(data,1,"","");
        map.put("title", "租赁商品："+commodity.getCommodityName());
        map.put("money",order.getTotalAmount());
        data.put("result", map);
        return data;
    }

    //购买商品生成验证信息
    private Map<String,Object> getTitleAndMoney2(String orderNo) {
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> param = new HashMap<>();
        param.put("orderCode", orderNo);
        Czjorder order = czjorderService.getOneBy(param);

        Czjorderdetail czjorderdetail = czjorderdetailService.queryByCode(orderNo);
        if(order==null){
            putData(data,0,"73","订单不存在");
            return data;
        }
        Czjcommodity commodity = czjcommodityService.queryById(czjorderdetail.getCommodityId());
        if(commodity.getDelFlag()==1||commodity.getSoldOut()==1){
            System.out.println(LocalDateTime.getDateStr(new Date())+"    "+"商品已下架，请手动取消订单！");
            putData(data,0,"71","商品已下架，请手动取消订单！");
            return data;
        }
        putData(data,1,"","");
        map.put("title", "购买商品："+commodity.getCommodityName());
        map.put("money",order.getTotalAmount());
        data.put("result", map);
        return data;
    }

    private void putData(Map<String, Object> data, int status, String code, String msg) {
        data.put("status",status);
        data.put("code",code);
        data.put("msg",msg);
    }



    /**
     * 微信支付完成回调函数
     */
    //重复通知过滤
    private static ExpireKey expireKey = new DefaultExpireKey();
    @RequestMapping("payMchNotify.jn")
    public void payMchNotify(HttpServletRequest request, HttpServletResponse response,
                             ModelMap model) throws IOException {
        try {
            String key = StaticMap.payKey;
            //获取请求数据
            String xmlData = StreamUtils.copyToString(request.getInputStream(), Charset.forName("utf-8"));
            //将XML转为MAP,确保所有字段都参与签名验证
            Map<String,String> mapData = XMLConverUtil.convertToMap(xmlData);
            //转换数据对象
            MchPayNotify payNotify = XMLConverUtil.convertToObject(MchPayNotify.class,xmlData);

            //已处理 去重
            if(expireKey.exists(payNotify.getTransaction_id())){
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("SUCCESS");
                baseResult.setReturn_msg("OK");
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
                return;
            }
            //签名验证
            if(SignatureUtil.validateSign(mapData,key)){
                //@since 2.8.5
                payNotify.buildDynamicField(mapData);

                expireKey.add(payNotify.getTransaction_id());
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("SUCCESS");
                baseResult.setReturn_msg("OK");
                try {
                    weixininfoService.insertWeixinVoucher(payNotify);//插入微信支付凭证到数据库
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("生成微信凭证失败！",e);
                }

                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            }else{
                MchBaseResult baseResult = new MchBaseResult();
                baseResult.setReturn_code("FAIL");
                baseResult.setReturn_msg("ERROR");
                response.getOutputStream().write(XMLConverUtil.convertToXML(baseResult).getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("生成微信凭证失败！2",e);
        }
    }

    /**
     * 获取微信配置信息
     * @param url
     * @param req
     * @param resp
     * @param model
     * @throws IOException
     */
    @RequestMapping("getInfo.do")
    public void getInfo(@RequestParam(required = true) String url,
                        HttpServletRequest req, HttpServletResponse resp,
                        ModelMap model) throws IOException {
        try {
//            url = "http://www.51d1d.com/chezhujie/html/jssdk/index.html";
            if(StaticMap.getAccessToken()==null){
                StaticMap.setAccessToken(new AccessToken());
            }
            AccessToken accessToken = StaticMap.getAccessToken();
            if(accessToken.getEndtime()==null||accessToken.getEndtime()<=System.currentTimeMillis()){
                String token = weixininfoService.getAccessToken();
                String ticket = weixininfoService.getTicket(token);
                accessToken.setAccess_token(token);
                accessToken.setTicket(ticket);
                accessToken.setCreatetime(new Date());
                accessToken.setEndtime(System.currentTimeMillis()+60*1000);
                accessToken.setExpires_in(0);
            }
            Map map = WeixininfoService.sign(accessToken.getTicket(), url,StaticMap.appid);

            jsonResult(1,"","",map,resp);
        } catch (Exception e) {
            e.printStackTrace();
            jsonResult(0,"00","出错："+e.getMessage(),"",resp);
        }
    }
    //退款
    @RequestMapping("refund.do")
    public void refund(@RequestParam(required = true) String orderno,
                        HttpServletRequest req, HttpServletResponse resp,
                        ModelMap model)  {
        try {
            SecapiPayRefundResult obj = weixininfoService.payRefund(orderno);
            if ("FAIL".equals(obj.getReturn_code())) {
                jsonResult(0, "11", obj.getReturn_msg(), "", resp);
                return;
            }
            if ("FAIL".equals(obj.getErr_code())) {
                jsonResult(0, "12", obj.getErr_code_des(), "", resp);
                return;
            }
            jsonResult(1, "2", "", "", resp);
        }catch (Exception ex){
            jsonResult(0, "99", "程序出错", "", resp);
        }
    }



}
